package game.source.gui.ship;

import game.source.gui.Animation;
import game.source.gui.GuiComponent;
import game.source.gui.PositionControl;
import game.source.ships.GuiShipInterface;
import game.source.util.Timer;
import game.source.util.TimerListener;

import java.awt.Point;
import java.awt.image.BufferedImage;

/**
 * GuiShip:
 * 	Classe que trata a parte gráfica das naves: 
 * 	 Cuida da animação, movimentação, exibição na tela.
 * */
public abstract class GuiShip extends GuiComponent implements TimerListener,GuiShipInterface{

	public enum AnimState{						//Indica em que estado está a animação
		TURN_LEFT,								//Virando para a esquerda
		TURN_RIGHT,								//Virando para a direita
		TURN_LEFT_CENTER,						//Voltando da esquerda para o centro
		TURN_RIGHT_CENTER,						//Voltando da direita para o centro
		CENTER,									//No Centro, sem movimento
		EXPLODE_START,							//Começo da explosão
		EXPLODE_END								//Fim da explosão
	}

	private Point 					p_first;		//Ponto superior esquerdo da imagem na tela
	private AnimState				state;			//Em que animação ela está
	private Timer					timer;			//COntrole de tempo para a animação
	private PositionControl			pControl;		//Controla a posição da nave no deslocamento (basicamente: velocidade)
	private CallBackShipInterface	ship;			//callback para ship


	public GuiShip(){
		this.state = AnimState.CENTER;
		this.p_first = new Point(0,0);									//Inicia ponto de de posicionamento da figura	
		this.timer = new Timer(this,41);								//Coloca o timer com 41 milissegundos ~ 24fps
    }

	@Override
	public void setVel(double velx, double vely) {
		this.pControl = new PositionControl(velx, vely, this.p_first);
	}

	@Override
	public void setShip(CallBackShipInterface ship){
		this.ship = ship;
	}

	/*Localização na tela*/
	@Override
	public int getX0(){
		return this.p_first.x;
	}

	@Override
	public int getY0(){
		return this.p_first.y;
	}

	/*Alterar a localização na tela*/
	private void setPosition(Point pos){//Posiciona de forma abrupta, para uso interno	
		this.p_first.x = pos.x - this.getWidth()/2;
		this.p_first.y = pos.y - this.getHeight()/2;
	}
	private Point getPosition(){//Retorna a posição do centro da imagem
		return new Point(this.p_first.x + this.getWidth()/2, this.p_first.y + this.getHeight()/2);		
	}

	@Override
	public void start(Point position){
		this.state = AnimState.CENTER;
		this.p_first.x = position.x - this.getWidth()/2;
		this.p_first.y = position.y - this.getHeight()/2;
		this.pControl.setPosition(position);
		this.pControl.setNextPosition(position);
		if(!this.timer.isAlive())
			this.timer.start();
	}

	@Override
	public void move(Point position){					//Atualiza de acordo com o controlador de posicionamento
		this.pControl.setNextPosition(position);
	}
	public void move(int x,int y){						//Atualiza de acordo com o controlador de posicionamento
		this.pControl.setNextPosition(new Point(x,y));
	}

	/*Controle da animação:*/
	public abstract Animation getAnimation();	
	public abstract int getFrame();
	public abstract void setFrame(int frame);
	public abstract int getTurnLeftStart();
	public abstract int getTurnLeftEnd();
	public abstract int getTurnRightStart();
	public abstract int getTurnRightEnd();
	public abstract int getExplosionStart();
	public abstract int getExplosionEnd();

	public AnimState getState(){
		return this.state;
	}
	public void setState(AnimState state){
		this.state = state;
	}

	/*Mostra na tela*/
	@Override
	public void show(long time){
		if(this.state != AnimState.EXPLODE_END){
			if(this.state != AnimState.EXPLODE_START){
				this.pControl.update(time);
				this.setPosition(this.pControl.getPosition());
				this.ship.setPosition(this.getPosition());
			}
			this.getGraphics().drawImage(this.getAnimation().getFrame(this.getFrame()), p_first.x, p_first.y, null);
		}else{
		}
	}

	/*Atualiza animação:*/
	@Override
	public synchronized void update(){
		if(this.state != AnimState.EXPLODE_START && this.state != AnimState.EXPLODE_END){
			Point pNow = this.pControl.getPosition();
			Point pNext = this.pControl.getNextPosition();
			if(pNow.x > pNext.x){
				switch (this.state) {
				case CENTER:
					this.state = AnimState.TURN_LEFT;
					break;
				case TURN_RIGHT:
					this.state = AnimState.TURN_RIGHT_CENTER;
				default:
					break;
				}				
			}else if(pNow.x < pNext.x){
				switch (this.state) {
				case CENTER:
					this.state = AnimState.TURN_RIGHT;
					break;
				case TURN_LEFT:
					this.state = AnimState.TURN_LEFT_CENTER;
				default:
					break;
				}
			}else{
				if(this.state == AnimState.TURN_LEFT){
					this.state = AnimState.TURN_LEFT_CENTER;
				}
				if(this.state == AnimState.TURN_RIGHT){
					this.state = AnimState.TURN_RIGHT_CENTER;
				}
			}
		}
		switch (this.state) {
		case CENTER:
			this.setFrame(0);
			break;
		case TURN_LEFT:
			if(this.getFrame() == 0){
				this.setFrame(this.getTurnLeftStart());
			}else if(this.getFrame() != this.getTurnLeftEnd()){
				this.setFrame(this.getFrame()+1);
			}
			break;
		case TURN_RIGHT:
			if(this.getFrame() == 0){
				this.setFrame(this.getTurnRightStart());
			}else if(this.getFrame() < this.getTurnRightEnd()){
				this.setFrame(this.getFrame()+1);
			}
			break;
		case TURN_LEFT_CENTER:
			if(this.getFrame() > this.getTurnLeftStart()+3){
				this.setFrame(this.getFrame()-4);
			}else{
				this.setFrame(0);
				this.state = AnimState.CENTER;
			}
			break;
		case TURN_RIGHT_CENTER:
			if(this.getFrame() > this.getTurnRightStart()+3){
				this.setFrame(this.getFrame()-4);
			}else{
				this.setFrame(0);
				this.state = AnimState.CENTER;
			}
			break;
		case EXPLODE_START:
			if(this.getFrame() < this.getExplosionStart() || this.getFrame() > this.getExplosionEnd()){
				this.setFrame(this.getExplosionStart());
				p_first.x = this.getPosition().x - (this.getAnimation().getFrame(this.getFrame()).getWidth()/2);
				p_first.y = this.getPosition().y - (this.getAnimation().getFrame(this.getFrame()).getHeight()/2);
			}else{
				this.setFrame(this.getFrame()+1);
			}
			if(this.getFrame() == this.getExplosionEnd()){
				this.state = AnimState.EXPLODE_END;
			}
			break;
		case EXPLODE_END:
			this.ship.endExplosion();
			this.setFrame(0);
			this.state = AnimState.CENTER;
			break;
		default:
			System.err.println("Erro! Sem estado na animação.");
			this.setFrame(0);
			break;
		}
	}

	@Override
	public byte	getPixelAlpha(int x,int y){
		BufferedImage img = this.getAnimation().getFrame(this.getFrame());
		int pixel = img.getRGB(x, y);
		byte alpha = (byte)((pixel >> 24) & 0xFF);
		return alpha;
	}

	@Override
	public void explosion() {
		this.state = AnimState.EXPLODE_START;
	}
	@Override
	public void start() {
		this.timer.start();		
	}
	@Override
	public void play() {
		this.timer.play();		
	}

	@Override
	public void pause() {
		this.timer.pause();

	}
	@Override
	public void end(){
		this.timer.end();
	}
	@Override
	public boolean isPaused() {
		return this.timer.isPaused();		
	}
}
